package top.tresman.cxxcommon.utils;

import jakarta.annotation.Resource;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;
import top.tresman.cxxcommon.config.AuthConfig;
import top.tresman.cxxcommon.contract.AuthContract;
import top.tresman.cxxcommon.contract.AuthPwdContract;
import top.tresman.cxxcommon.entity.LoginUserDTO;
import top.tresman.cxxcommon.entity.RoleDTO;
import top.tresman.cxxcommon.entity.constants.BaseRedisConstant;
import top.tresman.cxxcommon.exception.ApiException;

import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Component
public class AuthUtils implements Serializable {

    @Serial
    private static final long serialVersionUID = -5274661257242673715L;

    @Getter
    @Setter
    private static LoginUserDTO loginUser;

    @Resource
    private AuthConfig authConfig;

    @Resource
    private RedisUtils redisUtils;

    public LoginUserDTO loginByPwd(AuthPwdContract authPwdContract, String md5) {
        if (authPwdContract == null) {
            throw new ApiException("账号或密码错误");
        }

        if (!authPwdContract.chkPwd(md5)) {
            throw new ApiException("账号或密码错误");
        }

        return loginByModel(authPwdContract);
    }

    private LoginUserDTO loginByModel(AuthContract authContract) {
        String token = UUID.randomUUID().toString();

        loginUser = new LoginUserDTO();
        loginUser.setToken(token);

        LoginUserDTO.UserInfo userInfo = authContract.convertToUserInfo();
        loginUser.setUser(userInfo);

        cacheUser(loginUser, authContract);

        token = authContract.getTokenPrefix() + ":" + token;
        loginUser.setTokenPrefix(authContract.getTokenPrefix());
        loginUser.setToken(token);

        return loginUser;
    }

    public void cacheUser(LoginUserDTO loginUser, AuthContract authContract) {
        String token = loginUser.getToken();
        String tokenPrefix = authContract.getTokenPrefix();
        LoginUserDTO.UserInfo user = loginUser.getUser();
        String loginKey = BaseRedisConstant.getLoginKey(tokenPrefix, token);
        String tokenSetKey = BaseRedisConstant.getUserTokenSetKey(tokenPrefix, user.getId());

        handleRole(user, authContract);

        Long seconds = authConfig.getLoginExpireSec();
        redisUtils.set(loginKey, user, seconds);
        redisUtils.sAdd(tokenSetKey, token);
        redisUtils.expire(tokenSetKey, seconds);
    }

    private void handleRole(LoginUserDTO.UserInfo user, AuthContract authContract) {
        List<RoleDTO> roleList = authContract.getRoleList();
        if (CollectionUtils.isEmpty(roleList)) {
            throw new ApiException("此用户无角色，请联系管理员");
        }

        String roleMapKey = BaseRedisConstant.getRoleMapKey();
        List<Integer> roleIdList = new ArrayList<>(roleList.size());
        for (RoleDTO role : roleList) {
            redisUtils.hSet(roleMapKey, role.getId().toString(), role);
            roleIdList.add(role.getId());
        }

        redisUtils.expire(roleMapKey, 86400L);
        user.setRoleList(roleList);
        user.setRoleIdList(roleIdList);
        Integer lastRoleId;
        if (authContract.getLastRoleId() != null) {
            lastRoleId = authContract.getLastRoleId();
        } else {
            lastRoleId = roleIdList.getFirst();
        }

        user.setLastRoleId(lastRoleId);
        authContract.setLastRoleId(lastRoleId);
    }

    public void logout() {
        String token = loginUser.getToken();
        String tokenPrefix = loginUser.getTokenPrefix();
        LoginUserDTO.UserInfo user = loginUser.getUser();
        String loginKey = BaseRedisConstant.getLoginKey(tokenPrefix, token);
        String tokenSetKey = BaseRedisConstant.getUserTokenSetKey(tokenPrefix, user.getId());

        redisUtils.sRem(tokenSetKey, token);
        redisUtils.delete(loginKey);

        loginUser = null;
    }
}
